//  File:	 Date.cpp
//  Author:       Scott Nordmann & Lauren Wallace
//  Description:  Non-inline member function definitions.
#include "Date.h"
#include <cstdio>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>

using namespace std;

// default constructor: today's date
Date::Date()
{
	// get the current system time
	time_t now = time(0);

	// convert the raw time value into year/month/day/weekDay
	tm* today = localtime(&now);

	// the year in the tm is the number of years since 1900
	year = today->tm_year + 1900;

	// tm starts counting at 0 for month and weekday so add 1 to offset it to display properly
	month = today->tm_mon + 1;
	weekDay = today->tm_wday + 1;

	// however day of the month starts counting at 1 so we don't need to
	day = today->tm_mday;
}

Date::Date(const Date& d)
{
	setYear(d.getYear());
	setMonth(d.getMonth());
	setDay(d.getDay());
	setWeekDay(d.getWeekDay());
}

Date::Date(int y, int m, int d, int w)
{
	setYear(y);
	setMonth(m);
	setDay(d);

	if (w != -1)
	{
		while(true)
			cout << w;
		setWeekDay(w);
	}
	else
	{
		// get the weekday manually
		time_t now;
		time(&now);
		tm* time = localtime(&now);

		time->tm_year = y - 1900;
		time->tm_mon = m - 1;
		time->tm_mday = d;

		mktime(time);

		setWeekDay(time->tm_wday + 1);
	}
}

Date::~Date()
{
	vector<Event*>::iterator i;
	for (i = events.begin(); i != events.end(); ++i)
	{
		delete *i;
	}

	events.clear();
}

void Date::shutDown(ofstream& ofsave)
{
	if (!events.empty())
	{
		ofsave << getDateString() << endl;

		ofsave << events.size() << endl;

		vector<Event*>::iterator eiter;
		for (eiter = events.begin(); eiter != events.end(); ++eiter)
		{
			ofsave << (*eiter)->getCreatorName() << endl;
			ofsave << (*eiter)->getTitle() << endl;
			ofsave << (*eiter)->getContent() << endl;
			ofsave << (*eiter)->getTimeString() << endl;
		}
	}
}

string Date::getDateString() const
{
	ostringstream oss;

	oss << getMonth() << "/" << getDay() << "/" << getYear();

	return oss.str();
}

string Date::getWeekDayName(int weekDay)
{
	string weekDayName = "";

	switch (weekDay)
	{
	case 1:
		weekDayName = "Sunday";
		break;
	case 2:
		weekDayName = "Monday";
		break;
	case 3:
		weekDayName = "Tuesday";
		break;
	case 4:
		weekDayName = "Wednesday";
		break;
	case 5:
		weekDayName = "Thursday";
		break;
	case 6:
		weekDayName = "Friday";
		break;
	case 7:
		weekDayName = "Saturday";
		break;
	}

	return weekDayName;
}

int Date::getDaysInMonth(int month, int year)
{
	int numDays = 0;

	switch (month)
	{
	// January, March, May, July, August, October, December
	case 1:
	case 3:
	case 5:
	case 7:
	case 8:
	case 10:
	case 12:
		numDays = 31;
		break;
	// April, June, September, November
	case 4:
	case 6:
	case 9:
	case 11:
		numDays = 30;
		break;
	// February
	case 2:
		if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
			numDays = 29;
		else
			numDays = 28;
		break;
	}

	return numDays;
}

void Date::display()const
{
	cout << getWeekDayName(weekDay) << " " << getDateString();
}

void Date::displayEvents()const
{
	cout.fill(' ');
	cout << setw(10) << left << getWeekDayName(weekDay);

	cout.fill('0');
	cout << right << setw(2) << getMonth() << "/" << setw(2) << getDay() << "/" << getYear() << endl;

	cout.fill('-');
	cout << setw(79) << "-" << endl;

	if (!events.empty())
	{
		vector<Event*>::const_iterator i;
		for (i = events.begin(); i != events.end(); ++i)
		{
			(*i)->displaySummary();
		}
	}
	else
	{
		cout << "No events scheduled for this date." << endl;
	}

	cout.fill('-');
	cout << setw(79) << "-" << endl;
}

Event* Date::viewSpecificEvent() const
{
	Event* specificEvent = NULL;

	if (!events.empty())
	{
		int i = 1;
		vector<Event*>::const_iterator current;
		for (current = events.begin(); current != events.end(); ++current)
		{
			cout << "[" << i << "] ";
			(*current)->displaySummary();
			i++;
		}

		int viewEvent;
		cout << "Enter event number: ";
		cin >> viewEvent;

		--viewEvent;

		specificEvent = events[viewEvent];
	}
	else
	{
		cout << "No events scheduled for this date." << endl;
		specificEvent = NULL;
	}

	return specificEvent;
}

void Date::incrementDay(int numDays)
{
	if (numDays > 0)
	{
		for (int i = 0; i < numDays; i++)
		{
			day++;

			if (day > getDaysInMonth(month, year))
			{
				day = 1;
				month++;

				if (month > 12)
				{
					month = 1;
					year++;
				}
			}

			weekDay++;

			if (weekDay == 8)
				weekDay = 1;
		}
	}
}

void Date::decrementDay(int numDays)
{
	if (numDays > 0)
	{
		for (int i = 0; i < numDays; i++)
		{
			day--;

			if (day < 1)
			{
				month--;
			       
				if (month < 1)
				{
					month = 12;
					year--;
				}

				day = Date::getDaysInMonth(month, year);
			}


			weekDay--;

			if (weekDay == 0)
				weekDay = 7;
		}
	}
}

void Date::addEvent(Event* e)
{
	events.push_back(e);
}

void Date::deleteEvent(Event* e)
{
	vector<Event*>::iterator iter = events.begin();
	while (*iter != e && iter != events.end())
	{
		++iter;
	}

	if (iter != events.end())
	{
		events.erase(iter);
		delete e;
	}
}

Event* Date::findEvent(const string& eventTitle)
{
	Event* e = NULL;

	vector<Event*>::iterator iter = events.begin();
	while ((*iter)->getTitle() != eventTitle && iter != events.end())
	{
		++iter;
	}

	if (iter != events.end())
	{
		e = *iter;
	}
	
	return e;
}

Date Date::parseDate(const string& dateString)
{
	istringstream iss;

	// tokenize the string into parts for a year, month, and day
	string ystring;
	string mstring;
	string dstring;

	iss.str(dateString);

	getline(iss, mstring, '/');
	getline(iss, dstring, '/');
	getline(iss, ystring);

	// parse the strings into integers
	int year = 0;
	int month = 0;
	int day = 0;

	iss.clear();

	iss.str(ystring);
	iss >> year;

	iss.clear();

	iss.str(mstring);
	iss >> month;
	
	iss.clear();

	iss.str(dstring);
	iss >> day;

	// create and return a Date
	return Date(year, month, day);
}